﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WcfServer.Classes.Client;


namespace Client.View
{
    /// <summary>
    /// Interaction logic for DirecConnection.xaml
    /// </summary>
    public partial class DirectConnection : Page
    {
        public DirectConnection()
        {
            InitializeComponent();
        }

        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            Task.Factory.StartNew(delegate
            {
                var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint ipe = new IPEndPoint(IPAddress.Any, 24300);
                listener.Bind(ipe);
                listener.Listen(4);
                while (true)
                {
                    var soc = listener.Accept();
                    //String src_ip = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString();
                    Dispatcher.BeginInvoke((Action)(() =>
                    {
                        HandleAcceptedDirect(soc);
                    }));
                }
            });
        }

        private void Button_Click_5(object sender, RoutedEventArgs e)
        {
            Dispatcher.BeginInvoke((Action)(() =>
            {
                Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                soc.Connect(IPAddress.Parse(DirectIP.Text), 24300);

                DirectInitiator di = new DirectInitiator(SrcName.Text);

                FileStream fs = new FileStream(@"server_public.xml", FileMode.Open, FileAccess.Read);
                StreamReader sr = new StreamReader(fs);
                String XML = sr.ReadToEnd();

                InitMsgWrapper msg = new InitMsgWrapper()
                {
                    IsDirect = true,
                    EncryptedMessageContent = di.Send(XML)
                };

                soc.Send(msg.Send());

                byte[] buffer = new byte[10000]; //TODO: is 10KB enough?
                int bytesReceived = soc.Receive(buffer);

                byte[] data = new byte[bytesReceived];
                Buffer.BlockCopy(buffer, 0, data, 0, bytesReceived);

                Ack ack = new Ack(data, di.SessionKey);
                //TODO: VALIDATION.

                var dialogue = new ChatWindow(soc, di.SessionKey);
                dialogue.Show();
            }));

        }
        public void HandleAcceptedDirect(Socket soc)
        {
            byte[] buffer = new byte[10000]; //TODO: is 10KB enough?
            int bytesReceived = soc.Receive(buffer);

            byte[] data = new byte[bytesReceived];
            Buffer.BlockCopy(buffer, 0, data, 0, bytesReceived);

            InitMsgWrapper msg = new InitMsgWrapper(data);
            if (msg.IsDirect)
            {
                DirectInitiator di = new DirectInitiator(msg.EncryptedMessageContent, SrcName.Text);//TODO: what should be use for container name? 
                //TODO: Check Sign Validity. Check Every Validation! Do we need an error handling?
                Ack ack = new Ack()
                {
                    TimeStamp = di.TimeStamp.AddSeconds(1),//T+1
                };

                byte[] ackToSend = ack.Send(di.SessionKey);// Ks ( T )
                soc.Send(ackToSend);

                var dialogue = new ChatWindow(soc, di.SessionKey);
                dialogue.Show();
            }
        }

        private void GoBack(object sender, RoutedEventArgs e)
        {
            this.NavigationService.GoBack();
        }

    }
}
